package org.boulderfoodrescue.webapp.server.timeSlots;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Logger;

import org.boulderfoodrescue.webapp.shared.OneTimeEvent;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.FilterOperator;

public class OneTimeEventDatabase {
	private static final Logger log = Logger.getLogger(OneTimeEventDatabase.class.getName());

	public static Long addOneTimeEvent(OneTimeEvent event)
	{
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		Entity databaseOneTimeEvent = oneTimeEventToEntity(event);
		Long key = datastore.put(databaseOneTimeEvent).getId();
		event.setDatabaseKey(key);
		log.info("New one time event added to datbase");
		return key;
	}
	
	public static Long updateOneTimeEvent(OneTimeEvent event){
		Long key = null;
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		key =  datastore.put(oneTimeEventToEntity(event)).getId();
		return key;
	}

	public static List<OneTimeEvent> getOneTimeEvents(Long locationKey, int maxNumberToReturn){
		Query query = new Query("singleEvent");
		query.addFilter("locationKey", FilterOperator.EQUAL, locationKey);
		
		return queryOneTimeEventDatabase(query, maxNumberToReturn);
	}
	
	public static OneTimeEvent getOneTimeEvent(Long key)
	{
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		Entity databaseOneTimeEvent = new Entity("singleEvent", key);
		try {
			databaseOneTimeEvent = datastore.get(databaseOneTimeEvent.getKey());
		} catch (EntityNotFoundException e) {
			log.warning("Entity not found in database");
			return null;
		}
		OneTimeEvent event = entityToOneTimeEvent(databaseOneTimeEvent);
		return event;
	}
	
	public static List<OneTimeEvent> getOneTimeEvents(Date startDate, int maxNumberToReturn)
	{
		Query query = new Query("singleEvent");
		query.addFilter("startDate", FilterOperator.GREATER_THAN_OR_EQUAL, startDate);
		
		return queryOneTimeEventDatabase(query, maxNumberToReturn);
	}
	
	public static List<OneTimeEvent> getOneTimeEvents(Date startDate, Date endDate, int maxNumberToReturn)
	{
		Query query = new Query("singlEvent");
		query.addFilter("startDate", FilterOperator.GREATER_THAN_OR_EQUAL, startDate);
		query.addFilter("endDate", FilterOperator.LESS_THAN_OR_EQUAL, endDate);
		
		return queryOneTimeEventDatabase(query, maxNumberToReturn);
	}
	
	private static List<OneTimeEvent> queryOneTimeEventDatabase(Query query, int maxNumberToReturn)
	{
		List<OneTimeEvent> events = new LinkedList<OneTimeEvent>();
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		
		List<Entity> dEvents = datastore.prepare(query).asList(FetchOptions.Builder.withLimit(maxNumberToReturn));
		
		for(Entity dEvent : dEvents)
		{
			OneTimeEvent event = entityToOneTimeEvent(dEvent);
			events.add(event);
		}
		log.info("Retrieved single event info for "+events.size()+" events.");
		return events;
	}
	
	public static Boolean removeOneTimeToEntity(OneTimeEvent event)
	{
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		Entity databaseUser = new Entity("singleEvent", event.getDatabaseKey());
		datastore.delete(databaseUser.getKey());
		return true;
	}
	
	private static Entity oneTimeEventToEntity(OneTimeEvent event)
	{
		Entity databaseOneTimeEvent;
		if(event.getDatabaseKey() != null && event.getDatabaseKey() != 0)
			databaseOneTimeEvent = new Entity("singleEvent", event.getDatabaseKey());
		else
			databaseOneTimeEvent = new Entity("singleEvent");
		databaseOneTimeEvent.setProperty("allDay", event.getAllDay());
		databaseOneTimeEvent.setProperty("endTime", event.getEndTime());
		databaseOneTimeEvent.setProperty("startTime", event.getStartTime());
		databaseOneTimeEvent.setProperty("locationKey", event.getLocationKey());
		return databaseOneTimeEvent;
	}

	private static OneTimeEvent entityToOneTimeEvent(Entity entity)
	{
		OneTimeEvent oneTimeEvent = new OneTimeEvent();
		oneTimeEvent.setAllDay((Boolean) entity.getProperty("allDay"));
		oneTimeEvent.setEndTime((Date) entity.getProperty("endTime"));
		oneTimeEvent.setStartTime((Date) entity.getProperty("startTime"));
		oneTimeEvent.setLocationKey((Long) entity.getProperty("locationKey"));
		oneTimeEvent.setDatabaseKey(entity.getKey().getId());
		return oneTimeEvent;
	}
}
